/**
 *  X86Assembler.java : IceBird project
 *  19:11:16 
 */
package icebird.compiler.ncomp;

import java.io.OutputStream;
import java.util.ArrayList;

import icebird.compiler.ncomp.X86Register.FPU;
import icebird.metadata.Method;

/**
 * @author Sergey Shulepoff[Knott]
 */
public abstract class X86Assembler {
	
	protected boolean methodArea;
	
	
	
	public boolean isMethodArea() {
		return methodArea;
	}


	public void setMethodArea(boolean methodArea) {
		this.methodArea = methodArea;
	}


	protected X86Assembler() {
		asm = this;
	}

	private static X86Assembler asm;
	public static X86Assembler getAsm() {
		return asm;
	}
	
	
	public void clear(X86Register dst) {
		xor(dst, dst);
	}
	
	public abstract ArrayList<Label> defines();
	
	public abstract void xchg(X86Register dst, X86Register src);
	
	public abstract void push(int v);
	public abstract void push(X86Register reg, int offset);
	public abstract void push(X86Register reg);
	
	public abstract void pop(int v);
	public abstract void pop(X86Register reg, int offset);
	public abstract void pop(X86Register reg);
	
	public abstract void test(X86Register r0, X86Register r1);
	public abstract void cmp(X86Register r0, int v);
	public abstract void cmp(X86Register r0, X86Register r1);
	
	public abstract void move(X86Register dst, int v);
	public abstract void move(X86Register dst, X86Register src);
	public abstract void move(X86Register dst, int disp, X86Register src);
	public abstract void move(X86Register dst, X86Register src, int srcDisp);
	public abstract void move(X86Register dst, X86Register src, X86Register m, int scale, int disp);
	public abstract void move(X86Register dst, Label l, int disp);
	public abstract void move(X86Register dst, Label l);
	public abstract void move(Label l, int disp, X86Register src);
	public abstract void move(Label l, X86Register src);
	public abstract void move_const(X86Register dst, int v);
	public abstract void move_const(X86Register dst, int disp, int v);
	public abstract void movesx(X86Register dst, X86Register src);
	public abstract void movezx(X86Register dst, X86Register src);
	
	public abstract void lea(X86Register dst, X86Register src, int srcDisp);
	
	public abstract void fxch(FPU fp);
	public abstract void fistp(X86Register r, int srcDisp);
	public abstract void fild(X86Register r, int srcDisp);
	public abstract void fld(X86Register r, int srcDisp);
	public abstract void fstp(X86Register r, int srcDisp);
	
	public abstract void fistp64(X86Register r, int srcDisp);
	public abstract void fild64(X86Register r, int srcDisp);
	public abstract void fld64(X86Register r, int srcDisp);
	public abstract void fstp64(X86Register r, int srcDisp);
	
	public abstract void add(X86Register dst, X86Register src);
	public abstract void sub(X86Register dst, X86Register src);
	public abstract void and(X86Register dst, X86Register src);
	public abstract void xor(X86Register dst, X86Register src);
	public abstract void or(X86Register dst, X86Register src);
	
	public abstract void add(X86Register dst, X86Register src, int disp);
	public abstract void sub(X86Register dst, X86Register src, int disp);
	public abstract void and(X86Register dst, X86Register src, int disp);
	public abstract void xor(X86Register dst, X86Register src, int disp);
	public abstract void or(X86Register dst, X86Register src, int disp);
	
	public abstract void add(X86Register dst, int v);
	public abstract void sub(X86Register dst, int v);
	public abstract void and(X86Register dst, int v);
	public abstract void xor(X86Register dst, int v);
	public abstract void or(X86Register dst, int v);
	
	public abstract void sbb(X86Register dst, X86Register src);
	public abstract void sbb(X86Register dst, int v);
	
	public abstract void sar(X86Register dst, int shift);
	public abstract void sal(X86Register dst, int shift);
	public abstract void shl(X86Register dst, int shift);
	public abstract void shr(X86Register dst, int shift);
	public abstract void sar(X86Register dst, X86Register src);
	public abstract void sal(X86Register dst, X86Register src);
	public abstract void shld(X86Register dst, X86Register src);
	public abstract void shrd(X86Register dst, X86Register src);
	public abstract void shl(X86Register dst, X86Register shift);
	public abstract void shr(X86Register dst, X86Register shift);
	
	public abstract void idiv(X86Register dst);
	public abstract void imul(X86Register dst, X86Register src);
	public abstract void imul(X86Register dst, X86Register src, int v);
	
	public abstract void inc(X86Register dst);
	public abstract void inc(X86Register dst, int disp);
	public abstract void dec(X86Register dst);
	public abstract void dec(X86Register dst, int disp);
	
	public abstract void neg(X86Register r);
	public abstract void ret();
	
	public abstract void jmp(X86Register r, int disp);
	public abstract void jmp(Label l);
	public abstract void jcc(Label l, int cond);
	public abstract void call(Label l);
	
	public abstract void emit(OutputStream s);
	
	public abstract void header(Method source);
	public abstract void header();
	
	public abstract void bind(Label l);
	
	// Extern
	public abstract void extrn(Label l);
	public abstract void pblc(Label l);
	
	public abstract void dsp(int space);
	
	public final void arithOp(int op, X86Register dst, X86Register src) {
		switch (op) {
		case X86Operation.ADD:
			add(dst, src);
			break;
			
		case X86Operation.SUB:
			sub(dst, src);
			break;
			
		case X86Operation.AND:
			and(dst, src);
			break;
			
		case X86Operation.XOR:
			xor(dst, src);
			break;
			
		case X86Operation.OR:
			or(dst, src);
			break;
			
		default:
			throw new IllegalArgumentException("Illegal operation");
		}
	}
	
	public final void arithOp(int op, X86Register dst, X86Register src, int disp) {
		switch (op) {
		case X86Operation.ADD:
			add(dst, src, disp);
			break;
			
		case X86Operation.SUB:
			sub(dst, src, disp);
			break;
			
		case X86Operation.AND:
			and(dst, src, disp);
			break;
			
		case X86Operation.XOR:
			xor(dst, src, disp);
			break;
			
		case X86Operation.OR:
			or(dst, src, disp);
			break;
			
		default:
			throw new IllegalArgumentException("Illegal operation");
		}
	}
	
	public final void arithOp(int op, X86Register dst, int v) {
		switch (op) {
		case X86Operation.ADD:
			add(dst, v);
			break;
			
		case X86Operation.SUB:
			sub(dst, v);
			break;
			
		case X86Operation.AND:
			and(dst, v);
			break;
			
		case X86Operation.XOR:
			xor(dst, v);
			break;
			
		case X86Operation.OR:
			or(dst, v);
			break;
			
		default:
			throw new IllegalArgumentException("Illegal operation");
		}
	}
}
